package com.tmall.testgen.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;


import com.tmall.testgen.client.runinspring.push.jmx.DBInfoForJmx;
//import org.springframework.web.context.support.XmlWebApplicationContext;
import com.tmall.testgen.common.bo.interact.back.DBInfo;
import com.tmall.testgen.server.agent.Transformer4AOP;

/**
 * @author haojia
 * @date 2014-07-04
 */
public class ConfigExtractor {

	private static Object webApplicationContext ;
	
	private ClassLoader classLoader;
	
	public static String getBeanName(Class clazz){
		try{
		Object  webApplicationContext=getApplicationContext();
		
		Method  getBeansOfTypeMethod = webApplicationContext.getClass().getMethod("getBeansOfType", Class.class);
		
		Object beanMapObj=getBeansOfTypeMethod.invoke(webApplicationContext, clazz);
		
		if(beanMapObj!=null&&beanMapObj instanceof Map){
			Map beanMap=(Map) beanMapObj;
			if(beanMap.size()==0||beanMap.size()>1)
				return null;
			
			return (String) beanMap.keySet().iterator().next();
			
		}
		}catch(Exception e){
			return null;
		}
		return null;
	}
	
	private static ClassLoader getClassLoader(){
		return  Transformer4AOP.lastLoadedClass.getClassLoader();
	}
	/**
	 * 获取spring配置文件
	 * @param classLoader
	 * @return
	 */
	public static List<String> getSpringConfig(){
		List<String> result=new ArrayList<String>();
		try {
	    	Object  webApplicationContext=getApplicationContext();
	    	
	    	Method getServletContextMethod=webApplicationContext.getClass().getMethod("getServletContext");
	    	Object servletContextValue=getServletContextMethod.invoke(webApplicationContext);
	    	
	    	Method getAttributeNamesMethod=servletContextValue.getClass().getMethod("getAttributeNames");
	    	Object attributeNamesValue=getAttributeNamesMethod.invoke(servletContextValue);
	    	
	    	
	    	if(attributeNamesValue instanceof Enumeration){
	    		Enumeration attributeNamesEnumeration=(Enumeration) attributeNamesValue;
	    		while(attributeNamesEnumeration.hasMoreElements()){
	    			Method getAttributeMethod=servletContextValue.getClass().getMethod("getAttribute", String.class);
	    			Object attributeValue=getAttributeMethod.invoke(servletContextValue, (String)attributeNamesEnumeration.nextElement());
	    			try{
	    				Method getConfigLocationsMethod=attributeValue.getClass().getMethod("getConfigLocations");
	    				String[] locations=(String[]) getConfigLocationsMethod.invoke(attributeValue);
	    				for(String location:locations){
	    					result.add(location);
	    				}
	    			}catch(Exception e){
	    				
	    			}
	    		}
	    		
	    	}
		}catch(Exception e){
			e.printStackTrace();
		}
    	return result;
	}
	
	public static List<DBInfo>  getDB(Object webApplicationContext,ClassLoader classLoader){
		List<DBInfo>result=new ArrayList<DBInfo>();
		
		try {
			result.addAll(extractDBInfoInTDDL(webApplicationContext,classLoader));
		} catch (Exception e) {
			//e.printStackTrace();
		}
		
		try {
			result.addAll(extractDBInfoInBasic(webApplicationContext,classLoader));
			
		} catch (Exception e) {
		}
		
		return  result;
	}
	
	/**
	 * 获取数据库配置文件
	 * @param classLoader
	 * @return
	 */
	public static List<DBInfo>  getDB(){
	    	try{
			Object webApplicationContext= getApplicationContext();
			ClassLoader classLoader=getClassLoader();
			return getDB(webApplicationContext,classLoader);
	    	}catch(Exception e){
	    		return new ArrayList<DBInfo>();
	    	}
			
	}
	
	private static Object getApplicationContext(){
		ClassLoader classLoader=getClassLoader();
		
		if(webApplicationContext==null){
			try{
				Class ownerClass = Class.forName("org.springframework.web.context.ContextLoader",true,classLoader);
				Field field = ownerClass.getDeclaredField("currentContext");
				field.setAccessible(true);
				webApplicationContext= field.get(ownerClass);
			}catch(Exception e){
			}
		}
		return webApplicationContext;
	}
	
	private static List<DBInfo> extractDBInfoInBasic(Object webApplicationContext,ClassLoader classLoader) throws Exception{
		
		
		List<DBInfo>result=new ArrayList<DBInfo>();
		
		Method  getBeansOfTypeMethod = webApplicationContext.getClass().getMethod("getBeansOfType", Class.class);
		
		Class basicDataSourceClass= Class.forName("org.apache.commons.dbcp.BasicDataSource",true,classLoader);
		Object dataSourceObjs=getBeansOfTypeMethod.invoke(webApplicationContext, basicDataSourceClass);
		
		if(dataSourceObjs!=null&&dataSourceObjs instanceof Map){
			Map<String,Object> dataSourceMap=(Map<String, Object>) dataSourceObjs;
			for(String beanName:dataSourceMap.keySet()){
				Object dataSource=dataSourceMap.get(beanName);
				
				
				DBInfo info=new DBInfo(); 
				
				Method getUrl=basicDataSourceClass.getMethod("getUrl");
				info.setUrl((String) getUrl.invoke(dataSource));
				
				Method getUsername=basicDataSourceClass.getMethod("getUsername");
				info.setUserName((String) getUsername.invoke(dataSource));
				
				Method getPassword=basicDataSourceClass.getMethod("getPassword");
				info.setPassword((String) getPassword.invoke(dataSource));
				
				Method getDriverClassName=basicDataSourceClass.getMethod("getDriverClassName");
				info.setDriverClass((String) getDriverClassName.invoke(dataSource));
				
				result.add(info);
			}
		}
		return result;
	}
	
	
    private static  List<DBInfo> extractDBInfoInTDDL(Object webApplicationContext,ClassLoader classLoader) throws Exception{
    	List<DBInfo>result=new ArrayList<DBInfo>();
			
			
			Method  getBeansOfTypeMethod = webApplicationContext.getClass().getMethod("getBeansOfType", Class.class);
			
			Object dataGroupObjs=getBeansOfTypeMethod.invoke(webApplicationContext, Class.forName("com.taobao.tddl.jdbc.group.TGroupDataSource",true,classLoader));
			
			if(dataGroupObjs!=null&&dataGroupObjs instanceof Map){
				Map<String,Object> dataGroupMap=(Map<String, Object>) dataGroupObjs;
				for(String beanName:dataGroupMap.keySet()){
					Object tGroupDataSource=dataGroupMap.get(beanName);
					
					Field configManagerField=tGroupDataSource.getClass().getDeclaredField("configManager");
					configManagerField.setAccessible(true);
					Object configManagerValue=configManagerField.get(tGroupDataSource);
					
					
					Field dataSourceWrapperMapField=configManagerValue.getClass().getDeclaredField("dataSourceWrapperMap");
					dataSourceWrapperMapField.setAccessible(true);
					Object dataSourceWrapperMapValue=dataSourceWrapperMapField.get(configManagerValue);
					
					//========
					Field writeDBSelectorWrapperField=configManagerValue.getClass().getDeclaredField("writeDBSelectorWrapper");
					writeDBSelectorWrapperField.setAccessible(true);
					Object writeDBSelectorWrapperValue=writeDBSelectorWrapperField.get(configManagerValue);
					
					Field dataSourceMapField=writeDBSelectorWrapperValue.getClass().getDeclaredField("dataSourceMap");
					dataSourceMapField.setAccessible(true);
					Map<Object,Object> dataSourceMapValue=(Map<Object, Object>) dataSourceMapField.get(writeDBSelectorWrapperValue);
					
					
					
					for(Object key:dataSourceMapValue.keySet()){
						Object value=dataSourceMapValue.get(key);
						Field dswField=value.getClass().getField("dsw");
						Object dswValue=dswField.get(value);
						
						//判断是否有效===
						Field weightField=dswValue.getClass().getDeclaredField("weight");
						weightField.setAccessible(true);
						Object weightValue=weightField.get(dswValue);
						
						Field wField=weightValue.getClass().getDeclaredField("w");
						wField.setAccessible(true);
						int wValue=(Integer) wField.get(weightValue);
						if(wValue<=0)
							continue;
						//===============
						Field wrappedDataSourceField=dswValue.getClass().getDeclaredField("wrappedDataSource");
						wrappedDataSourceField.setAccessible(true);
						Object wrappedDataSourceValue=wrappedDataSourceField.get(dswValue);
						
						Field dsConfHandleField=wrappedDataSourceValue.getClass().getDeclaredField("dsConfHandle");
						dsConfHandleField.setAccessible(true);
						Object dsConfHandleValue=dsConfHandleField.get(wrappedDataSourceValue);
						try{
						Field druidDataSourceField=dsConfHandleValue.getClass().getDeclaredField("druidDataSource");
						druidDataSourceField.setAccessible(true);
						Object druidDataSourceValue=druidDataSourceField.get(dsConfHandleValue);
						
							
						Class druidClass=Class.forName("com.alibaba.druid.pool.DruidAbstractDataSource",true,classLoader);
						Field jdbcUrlField=druidClass.getDeclaredField("jdbcUrl");
						jdbcUrlField.setAccessible(true);
						String jdbcUrl=jdbcUrlField.get(druidDataSourceValue).toString();
						
						Field driverClassField=druidClass.getDeclaredField("driverClass");
						driverClassField.setAccessible(true);
						String driverClass=driverClassField.get(druidDataSourceValue).toString();
						
						
						
						Field usernameField=druidClass.getDeclaredField("username");
						usernameField.setAccessible(true);
						String username=usernameField.get(druidDataSourceValue).toString();
						
						Field passwordField=druidClass.getDeclaredField("password");
						passwordField.setAccessible(true);
						String password=passwordField.get(druidDataSourceValue).toString();
							
						DBInfo info=new DBInfo();
						info.setUrl(jdbcUrl);
						info.setUserName(username);
						info.setPassword(password);
						info.setDriverClass(driverClass);
						result.add(info);
						}catch(Exception e){
						    Field tAtomDsConfDOField= dsConfHandleValue.getClass().getDeclaredField("runTimeConf");
	                           tAtomDsConfDOField.setAccessible(true);
	                           Object tAtomDsConfDOValue=tAtomDsConfDOField.get(dsConfHandleValue);
	                           
	                           Field dbNameField=tAtomDsConfDOValue.getClass().getDeclaredField("dbName");
	                           dbNameField.setAccessible(true);
	                           String dbName=dbNameField.get(tAtomDsConfDOValue).toString();
	                           
	                           
	                           Field ipField=tAtomDsConfDOValue.getClass().getDeclaredField("ip");
	                           ipField.setAccessible(true);
	                           String ip=ipField.get(tAtomDsConfDOValue).toString();
	                           
	                           Field portField=tAtomDsConfDOValue.getClass().getDeclaredField("port");
	                           portField.setAccessible(true);
	                           String port=portField.get(tAtomDsConfDOValue).toString();
	                           
	                           
	                           String jdbcUrl="jdbc:mysql://"+ip+":"+port+"/"+dbName;
	                            
	                            
	                            Field usernameField=tAtomDsConfDOValue.getClass().getDeclaredField("userName");
	                            usernameField.setAccessible(true);
	                            String username=usernameField.get(tAtomDsConfDOValue).toString();
	                            
	                            Field passwordField=tAtomDsConfDOValue.getClass().getDeclaredField("passwd");
	                            passwordField.setAccessible(true);
	                            String password=passwordField.get(tAtomDsConfDOValue).toString();
	                            
	                            DBInfo info=new DBInfo();
	                            info.setUrl(jdbcUrl);
	                            info.setUserName(username);
	                            info.setPassword(password);
	                            info.setDriverClass("com.mysql.jdbc.Driver");
	                            result.add(info);
						}
						
					}
				}
			}
			return result;
		}
    
	
}
